package vn.mahjonggame.game.request;

import java.util.List;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.log4j.Logger;

import vn.mahjonggame.game.Mahjong;
import vn.mahjonggame.game.MahjongExtension;
import vn.mahjonggame.metadata.GameActionType;
import vn.mahjonggame.metadata.MatchState;
import vn.mahjonggame.metadata.Player;
import vn.mahjonggame.metadata.PlayerMode;
import vn.mahjonggame.metadata.Response;
import vn.mahjonggame.metadata.RoomVarName;
import vn.mahjonggame.metadata.TileSet;
import vn.mahjonggame.metadata.UserVarName;
import vn.mahjonggame.platform.GameplayConfig;
import vn.mahjonggame.platform.PlatformClient;

import com.smartfoxserver.v2.entities.Room;
import com.smartfoxserver.v2.entities.User;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSArray;
import com.smartfoxserver.v2.entities.data.SFSObject;
import com.smartfoxserver.v2.extensions.BaseClientRequestHandler;

public class CallRonHandler extends BaseClientRequestHandler {
	@Override
	public void handleClientRequest(User user, ISFSObject params) {
		final MahjongExtension ext = (MahjongExtension) getParentExtension();
		Mahjong mahjong = ext.getMahjong();
		List<User> users = user.getLastJoinedRoom().getUserList();
		Room room = ext.getGameRoom();
		Logger logger = mahjong.getLogger();		
		Player player = mahjong.getPlayerById(user.getId());		
		List<Player> players = mahjong.getPlayers();
		Player thrownPlayer = mahjong.getThrownPlayer();		
		List<Player> playerCanCallRons = mahjong.getCanCallRonPlayers();
		
		int roomBet = room.getVariable(RoomVarName.roomBet.toString()).getIntValue();
		
		/*
		 * Reset the player's timer
		 */
		player.cancelTimer();
		
		/*
		 * Increase the number of player that called RON, this values is used to determine if the MAHJONG is HOA
		 */
		int numRonPlayer = mahjong.getNumRonPlayer();
		numRonPlayer++;
		mahjong.setNumRonPlayer(numRonPlayer);
		
		/*
		 * The player has called RON
		 */
		player.setRon(true);
		
		mahjong.getCalledRonPlayers().add(player);		
		mahjong.setHasPlayerCalledRon(true);		
		
		Response.Builder response = new Response.Builder();		
		SFSArray sfsPlayerArray = new SFSArray();
		Response.Builder object = new Response.Builder();
		object.winPos(player.getPlayerPosition())
				.losePos(player.getPlayerPosition())
				.loseTile(-1)
				.winTile(-1);
		
		logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "CalledRonPlayers: " + mahjong.getCalledRonPlayers()));		
		
		if(playerCanCallRons.size() == numRonPlayer){
			
			/*
			 * Check if the MAHJONG is HOA
			 */
			if(mahjong.getCalledRonPlayers().size() == 3){
				
				for(int i = 0; i < players.size(); i++){
					
					Player iPlayer = players.get(i);					
					Response.Builder sfsUser = new Response.Builder();
					sfsUser.name(iPlayer.getName())
							.point(0)
							.money(0)
							.isWinner(false)
							.tiles(mahjong.tileArrayToTileIdArray(iPlayer.getLeftTiles()));
										
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "Player " + iPlayer.toString() + " " + iPlayer.getLeftTiles()));
					sfsPlayerArray.addSFSObject(sfsUser.build().getSFSObject());
				}				
				
				object.type(1);												
				response.HOA(object.build().getSFSObject())
						.players(sfsPlayerArray);
				
				SFSObject responseTmp = response.build().getSFSObject();
				logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "response: " + responseTmp));
				send(TileSet.HOA.toString(), response.build().getSFSObject(), users);				
				logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "Send HOA cmd to all users"));
				
				return;
			}
			
			/*
			 * The player that called RON will win 
			 */
			else if (mahjong.getCalledRonPlayers().size() > 0 && mahjong.getCalledRonPlayers().size() < 3){
				
				/*
				 * Calculate score for each called RON player
				 */
				for(Iterator<Player> iPlayers = playerCanCallRons.iterator(); iPlayers.hasNext();){
					Player iPlayer = iPlayers.next();
					
					if(!iPlayer.isRon()) continue;
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "Summary of : " + iPlayer.toString()));
					
					
					mahjong.calculateFuScore(iPlayer);
					mahjong.calculateScore(iPlayer);
					
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "HAN SCORE: " + iPlayer.getHanScore()));
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "YAKU: " + iPlayer.getYakuList()));
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "YAKUMAN: " + iPlayer.getYakumanList()));
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "OTHER YAKUMAN: " + iPlayer.getOtherYakumanList()));
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "FU SCORE: " + iPlayer.getFuScore()));					
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "SCORE: " + iPlayer.getScore()));
					
					double score = iPlayer.getScore();
					double transferScore = 0;
					
					if(iPlayer.getPlayerPosition() != 0){						
						transferScore = score * 4;						
					}
					else {
						transferScore = score * 6;
					}
					
					/*
					 * Round to multiple of 100
					 */
					transferScore = Math.round(transferScore / 100) * 100;
					
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "transferScore: " + transferScore));
					
					/*
					 * Minus the score of thrown player
					 */
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "finalScore of thrownPlayer: " + thrownPlayer.getFinalScore()));
					double finalScore = thrownPlayer.getFinalScore();
					finalScore = finalScore - transferScore;						
					thrownPlayer.setExtendedScore(-transferScore);
					thrownPlayer.setFinalScore(finalScore);
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "finalScore of thrownPlayer: " + thrownPlayer.getFinalScore()));
					
					/*
					 * Add the score for called RON player
					 */
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "finalScore: " + iPlayer.getFinalScore()));
					finalScore = iPlayer.getFinalScore();
					finalScore = finalScore + transferScore;
					iPlayer.setExtendedScore(transferScore);
					iPlayer.setFinalScore(finalScore);
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "finalScore: " + iPlayer.getFinalScore()));					
				}
				
				/*
				 * Call game_finish_game API
				 */
				if (ext.getPlayerMode() == PlayerMode.REAL_MODE.ordinal()){
					
					SFSObject res = mahjong.gameFinishGame(player, GameActionType.callRon.toString());
					
					if(res != null){
						send(GameActionType.callRon.toString(), res, users);
						return;
					}
				}
				
				for(int i = 0; i < players.size(); i++){
										
					Player iPlayer = players.get(i);
					User iUser = mahjong.getUserByPlayerId(iPlayer.getPlayerId(), users);
					
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "Build sfsUser for " + iPlayer.toString()));
					
					Response.Builder sfsUser = new Response.Builder();
					if(ext.getPlayerMode() == PlayerMode.REAL_MODE.ordinal() && iUser != null){						
						SFSObject res = mahjong.useGetBalance(sfsUser, iUser, iPlayer, GameActionType.callRon.toString());
						if(res != null){
							send(GameActionType.callRon.toString(), res, users);
							return;
						}
					}
					else{
						double amount = (iPlayer.getExtendedScore() * roomBet) / GameplayConfig.INIT_SCORE;
						sfsUser.money(amount);
						logger.info(mahjong.log(room, iPlayer, GameActionType.callRon.toString(), "amount: " + amount));
					}
									
					if(iPlayer.isRon()){
						sfsUser.isWinner(true);
					}
					else {
						sfsUser.isWinner(false);
					}		
					
					sfsUser.point(iPlayer.getExtendedScore())
							.name(iPlayer.getName())
							.tiles(mahjong.tileArrayToTileIdArray(iPlayer.getLeftTiles()));
					
					SFSObject sfsUserTmp = sfsUser.build().getSFSObject();
					logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "sfsUser: " + sfsUserTmp));
					sfsPlayerArray.addSFSObject(sfsUserTmp);
				}				
			}			
		}
		
		SFSObject objectTmp = object.build().getSFSObject();
		
		if(numRonPlayer == 3){			
			logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "Build HOA object: " + objectTmp));
			response.HOA(objectTmp);
		}
		else {
			logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "Build RON object: " + objectTmp));
			response.RON(objectTmp);			
		}
		
		Player nextCanCallRonPlayer = mahjong.getNextCanCallRonPlayer(player);
		
		int nextTurn;
		if(nextCanCallRonPlayer != null){			
			nextTurn = nextCanCallRonPlayer.getPlayerPosition();
		}
		else {
			nextTurn = player.getPlayerPosition();
		}
		
		response.turn(nextTurn)
				.players(sfsPlayerArray);
		
		send(GameActionType.callRon.toString(), response.build().getSFSObject(), users);		
		ext.addAction(user, GameActionType.callRon.toString());
		mahjong.getCanCallRonPlayers().remove(player);
		logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "nextTurn: " + nextTurn));
		logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "CanCallRonPlayers: " + mahjong.getCanCallRonPlayers()));
		if(nextCanCallRonPlayer == null){			
			ext.setMatchState(MatchState.SHOW_RESULT);
			logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "MatchState: " + ext.getMatchState()));
		}
		else {
			if(Boolean.valueOf(room.getVariable(RoomVarName.is_auto.toString()).getStringValue())){
				/*
				 * If the next turn player can call RON
				 */				
				int delay = Integer.valueOf(room.getVariable(RoomVarName.turn_time.toString()).getStringValue());
				final Response.Builder nextParams = new Response.Builder();
				nextParams.type(TileSet.RON.toString());				
				
				final User nextTurnUser = mahjong.getUserByPlayerId(nextCanCallRonPlayer.getPlayerId(), users);
				logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "nextTurnUser: " + nextTurnUser));							
				logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "Calling skip handler: " + delay));
				Timer timer = player.getTimer();
				timer.schedule(new TimerTask() {
					  @Override
					  public void run() {
						  SkipHandler skipHandler = new SkipHandler();
						  skipHandler.skip(ext, nextTurnUser, nextParams.build().getSFSObject(), true);								
					  }
				}, delay);
							
			}
		}
	}
}